package cn.shujuhai.common.config;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.thymeleaf.dialect.SaTokenDialect;
import cn.shujuhai.common.pluging.exception.UnknownPathException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {


    private final RateLimitInterceptor rateLimitInterceptor;

    private final SecurityProperties securityProperties;

    public SaTokenConfigure(RateLimitInterceptor rateLimitInterceptor, SecurityProperties securityProperties) {
        this.rateLimitInterceptor = rateLimitInterceptor;
        this.securityProperties = securityProperties;
    }


    // 注册 Sa-Token 的拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(rateLimitInterceptor).addPathPatterns("/**");

        // 后端的权限校验拦截器
        registry.addInterceptor(new SaInterceptor(handle -> {
                    // 限制请求方法
                    String method = SaHolder.getRequest().getMethod().toUpperCase();
                    if (!"GET".equals(method) && !"POST".equals(method)) {
                        throw new UnknownPathException("非法请求方法");
                    }
                    String host = SaHolder.getRequest().getHeader("Host");
                    if (host != null && !securityProperties.getHostWhitelist().contains(host)) {
                        throw new UnknownPathException("非法请求来源（Host）");
                    }
                    Set<Pattern> knownPaths = getKnownPaths();
                    String requestPath = SaHolder.getRequest().getRequestPath();
                    boolean isKnownPath = knownPaths.stream().anyMatch(pattern -> pattern.matcher(requestPath).matches());
                    if (!isKnownPath) {
                        throw new UnknownPathException("抱歉，你访问的页面不存在或仍在开发中");
                    }
                    SaRouter.match("/**")
                            .notMatch("/user/login")
                            .notMatch("/cms/column/search")
                            .notMatch("/cms/infoArticle/countArticleNum")
                            .notMatch("/cms/channel/countChannelNum")
                            .notMatch("/error/**")
                            .notMatch("/captcha/**")
                            .notMatch("/")
                            .notMatch("/workflow/form/getFormById")
                            .notMatch("/workflow/formData/addFormData")
                            .notMatch("/workflow/formData/uploadImg")
                            .notMatch("/workflow/formData/uploadFile")
                            .notMatch("/workflow/formData/uploadIceImg")
                            .check(r -> StpUtil.checkLogin());

                    Map<String, String> rules = getAuthRules();
                    for (Map.Entry<String, String> rule : rules.entrySet()) {
                        SaRouter.match(rule.getKey(), () -> StpUtil.checkPermission(rule.getValue()));
                    }
                })).addPathPatterns("/**")
                .excludePathPatterns("/page/login", "/pear/**", "/site/**", "/channel/**", "/article/**", "/upload/**", "/workflow/**",
                        "/vm/**", "/page/common/error/**");
    }

    // 动态获取鉴权规则
    public Map<String, String> getAuthRules() {
        Map<String, String> authMap = new LinkedHashMap<>();
        String[] cmsEntities = {"template", "channel", "infoArticle", "email", "group", "recipient", "struct"};
        String[] commonEntities = {"user", "role", "menu", "setting", "permission", "department"};
        String[] workflowEntities = {"flowDefinition", "processDeploy", "flowable", "form"};
        String[] meetingEntities = {"equipment", "meetRoom", "reservation"};
        String[] actions = {"list", "add", "delete", "update", "select"};

        for (String entity : cmsEntities) {
            for (String action : actions) {
                String path = "/cms/";
                if ("delete".equals(action) || "update".equals(action) || "select".equals(action)) {
                    path += entity + "/" + action + "/(.*)";
                } else {
                    path += entity + "/" + action;
                }
                authMap.put(path, entity + "_" + action);
            }
            authMap.put("/" + entity + "/enable/(.*)", entity + "_enable");
        }

        for (String entity : commonEntities) {
            for (String action : actions) {
                String path = "/";
                if ("delete".equals(action) || "update".equals(action) || "select".equals(action)) {
                    path += entity + "/" + action + "/(.*)";
                } else {
                    path += entity + "/" + action;
                }
                authMap.put(path, entity + "_" + action);
            }
            authMap.put("/" + entity + "/enable/(.*)", entity + "_enable");
        }
        // workflow 模块
        for (String entity : workflowEntities) {
            for (String action : actions) {
                String path = "/workflow/";
                if ("delete".equals(action) || "update".equals(action) || "select".equals(action)) {
                    path += entity + "/" + action + "/(.*)";
                } else {
                    path += entity + "/" + action;
                }
                authMap.put(path, entity + "_" + action);
            }
            authMap.put("/workflow/" + entity + "/enable/(.*)", entity + "_enable");
        }

// meeting 模块
        for (String entity : meetingEntities) {
            for (String action : actions) {
                String path = "/meeting/";
                if ("delete".equals(action) || "update".equals(action) || "select".equals(action)) {
                    path += entity + "/" + action + "/(.*)";
                } else {
                    path += entity + "/" + action;
                }
                authMap.put(path, entity + "_" + action);
            }
            authMap.put("/meeting/" + entity + "/enable/(.*)", entity + "_enable");
        }
        return authMap;
    }

    // 获取系统中存在的所有路径
    public Set<Pattern> getKnownPaths() {
        Set<Pattern> paths = new HashSet<>();

        // 添加其他已知路径
        paths.add(Pattern.compile("/"));
        paths.add(Pattern.compile("/cms/.*"));
        paths.add(Pattern.compile("/elfinder/.*"));
        paths.add(Pattern.compile("/captcha/.*"));
        paths.add(Pattern.compile("/workflow/.*"));
        paths.add(Pattern.compile("/meeting/.*"));
        paths.add(Pattern.compile("/department/.*"));
        paths.add(Pattern.compile("/vm/.*"));
        paths.add(Pattern.compile("/user/.*"));
        paths.add(Pattern.compile("/role/.*"));
        paths.add(Pattern.compile("/menu/.*"));
        paths.add(Pattern.compile("/setting/.*"));
        paths.add(Pattern.compile("/permission/.*"));
        paths.add(Pattern.compile("/visitCount/.*"));
        paths.add(Pattern.compile("/config"));
        paths.add(Pattern.compile("/log/.*"));
        paths.add(Pattern.compile("/page/.*"));
        paths.add(Pattern.compile("/pear/.*"));
        paths.add(Pattern.compile("/site/.*"));
        paths.add(Pattern.compile("/channel/.*"));
        paths.add(Pattern.compile("/article/.*"));
        paths.add(Pattern.compile("/upload/.*"));
        paths.add(Pattern.compile("/error/.*"));

        return paths;
    }

    // Sa-Token 标签方言 (Thymeleaf版)
    @Bean
    public SaTokenDialect getSaTokenDialect() {
        return new SaTokenDialect();
    }

}
